/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ufpb.compiladores.sintatico.graph;

import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.model.mxGraphModel;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.util.mxUtils;
import com.mxgraph.view.mxEdgeStyle;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxStylesheet;
import java.awt.Color;
import java.awt.Component;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
import java.util.Stack;

/**
 *
 * @author Sarah
 */
public class SyntaticalTree {

    private mxGraph graph = new mxGraph();
    Object parent = null;
    private mxCell r = null;
    private mxCell current = null;
    private ArrayList<mxCell> voltar = new ArrayList<mxCell>();
    private ArrayList<mxCell> ir = new ArrayList<mxCell>();
    private ArrayList<mxCell> voltarw = new ArrayList<mxCell>();
    private ArrayList<ArrayList<mxCell>> ar = new ArrayList<ArrayList<mxCell>>();
    private int cnivel = 0;
    private Stack<Integer> p = new Stack<Integer>();
    private Stack<mxCell> e = new Stack<mxCell>();
    private ArrayList<mxCell> el = new ArrayList<mxCell>();
    private ArrayList<mxCell> ww = new ArrayList<mxCell>();
    private Stack<String> tds = new Stack<String>();
    private boolean fechouwhile = false;



    public SyntaticalTree(){

        parent = graph.getDefaultParent();
        graph.getModel().beginUpdate();
        createStyles();
    }

    public final void createStyles(){

        Hashtable<String, Object> style0 = new Hashtable<String, Object>();
        Hashtable<String, Object> style1 = new Hashtable<String, Object>();
        Hashtable<String, Object> style2 = new Hashtable<String, Object>();
        Hashtable<String, Object> style3 = new Hashtable<String, Object>();
        Hashtable<String, Object> style4 = new Hashtable<String, Object>();
        Hashtable<String, Object> style5 = new Hashtable<String, Object>();

        Hashtable<String, Object> ed1 = new Hashtable<String, Object>();
        Hashtable<String, Object> ed2 = new Hashtable<String, Object>();

        mxStylesheet stylesheet = graph.getStylesheet();

    //    ed1.put(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ORTHOGONAL);
   //     stylesheet.putCellStyle("Ed1", ed1);

        ed2.put(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD);
        ed2.put(mxConstants.STYLE_FONTCOLOR, mxUtils.getHexColorString(Color.BLACK));
        ed2.put(mxConstants.STYLE_ALIGN,mxConstants.ALIGN_CENTER);
        ed2.put(mxConstants.STYLE_FONTSIZE,"15");
        ed2.put(mxConstants.STYLE_EDGE, mxConstants.EDGE_SELECTION_STROKE);
        stylesheet.putCellStyle("Ed2", ed2);

        style0.put(mxConstants.STYLE_FILLCOLOR, mxUtils.getHexColorString(new Color(170, 233, 143)));
        style0.put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_ELLIPSE);
        style0.put(mxConstants.STYLE_AUTOSIZE, "true");
        style0.put(mxConstants.STYLE_STROKEWIDTH, 0);
        style0.put(mxConstants.STYLE_SHADOW, true);

        style0.put(mxConstants.STYLE_FONTCOLOR, mxUtils.getHexColorString(Color.BLACK));
        style0.put(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD);
        stylesheet.putCellStyle("Begin", style0);

        style1.put(mxConstants.STYLE_FILLCOLOR, mxUtils.getHexColorString(new Color(243,143,143)));
        style1.put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_ELLIPSE);
        style1.put(mxConstants.STYLE_STROKEWIDTH, 0);
        style1.put(mxConstants.STYLE_SHADOW, true);

        style1.put(mxConstants.STYLE_FONTCOLOR, mxUtils.getHexColorString(Color.BLACK));
        style1.put(mxConstants.STYLE_FONTSTYLE, mxConstants.FONT_BOLD);
        stylesheet.putCellStyle("End", style1);

        style2.put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_RECTANGLE);
        style2.put(mxConstants.STYLE_ROUNDED, true);
        style2.put(mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
        style2.put(mxConstants.STYLE_STROKEWIDTH, 1);
        style2.put(mxConstants.STYLE_SHADOW, true);
        style2.put(mxConstants.STYLE_FONTCOLOR, mxUtils.getHexColorString(Color.BLACK));
        stylesheet.putCellStyle("Comando", style2);

        style3.put(mxConstants.STYLE_FILLCOLOR, mxUtils.getHexColorString(new Color(255,242,134)));
        style3.put(mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
        style3.put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_RHOMBUS);
        style3.put(mxConstants.STYLE_STROKEWIDTH, 0);
        style3.put(mxConstants.STYLE_FONTCOLOR, mxUtils.getHexColorString(Color.BLACK));
        stylesheet.putCellStyle("If", style3);

        style4.put(mxConstants.STYLE_FILLCOLOR, mxUtils.getHexColorString(new Color(252,159,84)));
        style4.put(mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
        style4.put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_RHOMBUS);
        style4.put(mxConstants.STYLE_STROKEWIDTH, 0);
        style4.put(mxConstants.STYLE_FONTCOLOR, mxUtils.getHexColorString(Color.BLACK));
        style4.put(mxConstants.STYLE_PORT_CONSTRAINT,"east");
        stylesheet.putCellStyle("While", style4);

        style5.put(mxConstants.STYLE_FILLCOLOR, mxUtils.getHexColorString(Color.BLACK));
        style5.put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_ELLIPSE);
        style5.put(mxConstants.STYLE_STROKEWIDTH, 0);
        style5.put(mxConstants.STYLE_PORT_CONSTRAINT,"east");
        stylesheet.putCellStyle("Ponto", style5);



    }

    public Component getComponent(){

      graph.getModel().endUpdate();
      mxHierarchicalLayout mx = new mxHierarchicalLayout(graph);
      mx.setDisableEdgeStyle(false);
      mx.execute(graph.getDefaultParent());
      mxGraphComponent mxc = new mxGraphComponent(graph);
      mxc.setEnabled(false);
      mxRectangle m = new mxRectangle();
    //  m = graph.getMinimumGraphSize();
     // System.out.println(m.getHeight() +" "+m.getWidth());
      
      return mxc;
    }

    public void insereNivel(mxCell n, int nivel){

        if (ar.size() >= nivel){

            ArrayList<mxCell> temp = new ArrayList<mxCell>();
            temp.add(n);
            ar.add(temp);
        } else {

            mxCell m = n;
            ar.get(nivel).add(m);
        }
    }

    public void textoEdge(mxCell e){

        if (!tds.isEmpty()){
            if (tds.peek().equals("if")){

                String temp = tds.pop() + "1";
                tds.push(temp);
                e.setValue("V");

            } else if (tds.peek().equals("else")){

                String temp = tds.pop() + "1";
                tds.push(temp);
                e.setValue("F");

            } else if (tds.peek().equals("while")){

                String temp = tds.pop() + "1";
                tds.push(temp);
                e.setValue("V");

            } else if (tds.peek().equals("if1")){

                tds.pop();
                e.setValue("F");

            } else if (tds.peek().equals("else1")){

                tds.pop();
                e.setValue("F");

            } else if (tds.peek().equals("while1")){

                tds.pop();
                e.setValue("F");
            }
        }
    }

    public void addCommand (String conteudo){

        mxCell nova = (mxCell) graph.insertVertex(parent, null, conteudo, 10,10,50,50, "Comando");
        graph.resizeCell(nova, new mxRectangle(10,20,6.5*conteudo.length(),25));

        mxCell e = (mxCell) graph.insertEdge(parent, null, null, current, nova, "Ed2");

        if (!tds.isEmpty()){
            if (tds.peek().equals("if")){

                String temp = tds.pop() + "1";
                tds.push(temp);
                e.setValue("V");

            } else if (tds.peek().equals("else")){

                String temp = tds.pop() + "1";
                tds.push(temp);
                e.setValue("F");

            } else if (tds.peek().equals("while")){

                String temp = tds.pop() + "1";
                tds.push(temp);
                e.setValue("V");
            }

        }

//        if (fechouwhile){
//
//            mxCell ed = (mxCell) graph.insertEdge(parent, null, null, voltarw.get(voltarw.size()-1), current, "Ed2");
//            voltarw.remove(voltarw.size()-1);
//            fechouwhile = false;
//            ed.setValue("F");
//        }

        cnivel++;
        insereNivel(nova, cnivel);
        current = nova;


    }

    public void addIf (String conteudo){

        mxCell nova = (mxCell) graph.insertVertex(parent, "If", conteudo, 10,10,50,50, "If");

            graph.resizeCell(nova, new mxRectangle(10,20,6.5*conteudo.length(),6.5*conteudo.length()/1.5));
        
        mxCell e = (mxCell) graph.insertEdge(parent, null, null, current, nova, "Ed2");

        if (!tds.isEmpty()){
            if (tds.peek().equalsIgnoreCase("else"))//current.getValue().toString().equalsIgnoreCase("If")){
                e.setValue("F");
       }

        //textoEdge(e);
        current = nova;
        voltar.add(nova);
        cnivel++;
        insereNivel(nova,cnivel);
        p.push(cnivel);
        tds.push("if");
    }
    
    public void addElse (){
       
        current = voltar.get(voltar.size()-1);
        voltar.remove(voltar.size()-1);
        tds.push("else");
    }
    
    public void fechaElse (){

        if (ww.isEmpty()){

            graph.insertEdge(parent, null, null, current, ir.get(ir.size()-1));
            current = ir.get(ir.size()-1);
            ir.remove(ir.size()-1);
            el.add(current);
        } else {

            ww.remove(ww.size()-1);
        }
    }
    
    public void fechaIf (){
        
        mxCell e = (mxCell) graph.insertEdge(parent, null, null, voltar.get(voltar.size()-1), ir.get(ir.size()-1), "Ed2");
        e.setValue("F");
        ir.remove(ir.size()-1);
        voltar.remove(voltar.size()-1);
        cnivel = p.pop();
    }

    public void addWhile (String conteudo){

        mxCell nova = (mxCell) graph.insertVertex(parent, "While", conteudo, 10,10,50,50, "While");

        graph.resizeCell(nova, new mxRectangle(10,20,6.5*conteudo.length(),6.5*conteudo.length()/1.5));

        mxCell e = (mxCell) graph.insertEdge(parent, null, null, current, nova, "Ed2");

        if (!tds.isEmpty()){
        if (tds.peek().equalsIgnoreCase("else"))//current.getValue().toString().equalsIgnoreCase("If")){

            e.setValue("F");
       }

      //  textoEdge(e);
        current = nova;
        voltarw.add(nova);
        cnivel++;
        insereNivel(nova,cnivel);
        tds.push("while");
    }

    public void fechaWhile (){

        this.addPoint();
        mxCell e = (mxCell) graph.insertEdge(parent, null, null, current, voltarw.get(voltarw.size()-1), "Ed2");
        voltarw.remove(voltarw.size()-1);
        fechouwhile = true;

        if (el.isEmpty()){

            ww.add(current);

            //graph.insertEdge(parent, null, null, voltarw.get(voltarw.size()-1), current);

            if (!ir.isEmpty()){

                if (!(current == ir.get(ir.size()-1)))
                    graph.insertEdge(parent, null, null, current, ir.get(ir.size()-1));

                if (voltar.isEmpty()){

                    current = ir.get(ir.size()-1);
                    ir.remove(ir.size()-1);
                }
            }

        } else {

            el.remove(el.size()-1);
        }


    }

    public void addBegin (){

        mxCell nova = (mxCell) graph.insertVertex(parent, null, "Início", 550,325,50,50, "Begin");
        current = nova;
        insereNivel(nova,cnivel);
    }
    
    public void addEnd (){
        
        mxCell nova = (mxCell) graph.insertVertex(parent, null, "Fim", 10,10,50,50, "End");
        mxCell e = (mxCell) graph.insertEdge(parent, null, null, current, nova, "Ed2");
        //textoEdge(e);
        current = nova;
        cnivel++;
        insereNivel(nova, cnivel);
    }

    public void addPoint (){

        mxCell nova = (mxCell) graph.insertVertex(parent, null, "", 10,10,15,15, "Ponto");
        if (!(current == nova)){
            mxCell e = (mxCell) graph.insertEdge(parent, null, null, current, nova, "Ed2");
        }
       // textoEdge(e);

        current = nova;

        if (!voltar.isEmpty()){

            ir.add(nova);
        }
        cnivel++;
        insereNivel(nova,cnivel);

    }
}
